﻿using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Net;
using CmdTailCmd;
using regxExtensions;

namespace regx
{
    class SearchUrlParams : RegxParams, ICmdTailCommand
    {
        public bool IsValid(CmdTailContext ctx)
        {   //-----------------------------------------------------------------
            return (Url.IsNotEmpty() && Pattern != null);
        }

        [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "Fusking", Justification = "Fusking *is* spelled correctly")]
        public bool Execute(object o) 
        {   //-----------------------------------------------------------------
            if (!InitializeExecution(Sources.Single)) return false;
            
            ErrorLevel el  = o as ErrorLevel;
            
            // Not sure what I think of this, style-wise, but it is kind of handy.
            IEnumerable<string> urls = Fusk ? Fusker.Expand(Url) : new string[] {Url};

            if (Fusk && urls.Count() == 0)
            {
                DisplayError("Error: The fusk pattern could not be expanded or yielded no urls");
                el.Set(ErrorLevelValue.Error);
                return false;
            }
            
            if (Debug)
            {
                // Show regex info
                _searcher.DebugOut();
                
                // Show output format info
                RegexResultFormatter rrf = MakeFormatter(urls.First());
                rrf.DebugOut();

                if (Fusk) Console.WriteLine("Fusking Url: " + Url);
                Console.WriteLine("Searching url(s):");
                foreach (string u in urls) Console.WriteLine("    " + u);

                el.Set(ErrorLevelValue.NoError);
                return true;
            }

            el.Set(ErrorLevelValue.NoMatch);
            foreach (string src in urls)
            {
                ErrorLevelValue elv = ProcessUrl(src);
                if (elv == ErrorLevelValue.Matched) el.Set(ErrorLevelValue.Matched);
                if (elv == ErrorLevelValue.Error)
                {
                    el.Set(ErrorLevelValue.Error);
                    return false;
                }                
            }
            return true;
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification="Catching the error to display and prevent a stack dump")]
        protected ErrorLevelValue ProcessUrl(string UrlToSearch)
        {   //-----------------------------------------------------------------
            try
            {
                Uri uri;
                if (!Uri.TryCreate(UrlToSearch, UriKind.Absolute, out uri)) uri = new Uri(@"http://" + UrlToSearch);
                WebRequest request = WebRequest.Create(uri);
            
                RegexResultFormatter rrf = MakeFormatter(uri.ToString());

                ErrorLevelValue elv = ErrorLevelValue.NoMatch;
                using (WebResponse response = request.GetResponse())
                {
                    Stream stm = response.GetResponseStream();
                
                    foreach (LineMatches lm in _searcher.MatchResults(stm))
                    {
                        if (lm.Matches.Count > 0) elv = ErrorLevelValue.Matched;
                        foreach (string line in rrf.FormatLineMatches(lm)) Console.WriteLine(line);
                    }                    
                }
                return elv;
            }
            catch (UriFormatException)
            {
                DisplayError("Error: The specified Url is invalid: " + UrlToSearch);
            }
            catch (NotSupportedException)
            {
                DisplayError("Error: The specified Url uses an unsupported scheme: " + UrlToSearch);
            }
            catch (WebException)
            {
                DisplayError("Error: An error occurred while retrieving the Url " + UrlToSearch);
            }
            catch (ProtocolViolationException)
            {
                DisplayError("Error: a protocol violation error occurred accessing the Url " + UrlToSearch);
            }
            catch (Exception e)
            {
                DisplayError("Error: An unknown error occurred. The error message is '" + e.Message + "'");
            }

            return ErrorLevelValue.Error;
        }
    
    }
}
